{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "242209b4-f1d2-4835-89e5-10ded04caa36",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import statsmodels.formula.api as smf\n",
    "import matplotlib.pyplot as plt\n",
    "import statsmodels.api as sm\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a7a697d-0a87-4f73-b484-53c19e846dc5",
   "metadata": {},
   "source": [
    "# 1. vignette base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "192f1682-31e8-42bb-88f6-adb3ebfa1372",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_excel(r\"\\df.xlsx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61eccb1d-34af-496d-93da-ee298e226a72",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "df[\"vignette_treatment\"] = df[\"vignette_treatment\"].astype(\"category\")\n",
    "df[\"gender\"] = df[\"gender\"].astype(\"category\")\n",
    "\n",
    "# ===================================================================\n",
    "# 1. full summary (WITH controls)\n",
    "# ===================================================================\n",
    "\n",
    "outcomes = [\n",
    "    \"legitimacy_vignette\",\n",
    "    \"fairness_vignette\",\n",
    "    \"trust_vignette\",\n",
    "    \"acceptance_vignette\"\n",
    "]\n",
    "\n",
    "control_vars = (\n",
    "    \" + age\"\n",
    "    \" + C(gender)\"\n",
    "    \" + income_cat\"\n",
    "    \" + living_with_spouse\"\n",
    "    \" + home_owner\"\n",
    "    \" + settlement_size\"\n",
    "    \" + years_in_korea\"\n",
    ")\n",
    "\n",
    "models = {}\n",
    "\n",
    "for outcome in outcomes:\n",
    "    formula = f\"{outcome} ~ C(vignette_treatment)\" + control_vars\n",
    "    model = smf.ols(formula, data=df).fit()\n",
    "    models[outcome] = model\n",
    "    print(f\"\\n================ {outcome} =================\")\n",
    "    print(model.summary())\n",
    "\n",
    "# ===================================================================\n",
    "# 2. 4 outcome multi-panel coef plot (controls , treatment)\n",
    "# ===================================================================\n",
    "\n",
    "coef_list = []\n",
    "se_list = []\n",
    "label_list = []\n",
    "\n",
    "for outcome in outcomes:\n",
    "    model = models[outcome]\n",
    "    treat_idx = [i for i in model.params.index if \"vignette_treatment\" in i]\n",
    "    coefs = model.params[treat_idx]\n",
    "    ses = model.bse[treat_idx]\n",
    "    \n",
    "    coef_list.append(coefs)\n",
    "    se_list.append(ses)\n",
    "    label_list.append(treat_idx)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(12, 8))\n",
    "axes = axes.flatten()\n",
    "\n",
    "titles = [\n",
    "    \"(a) Legitimacy\",\n",
    "    \"(b) Fairness\",\n",
    "    \"(c) Trust\",\n",
    "    \"(d) Acceptance\"\n",
    "]\n",
    "\n",
    "for i, ax in enumerate(axes):\n",
    "    coefs = coef_list[i]\n",
    "    ses = se_list[i]\n",
    "    labels = label_list[i]\n",
    "    y_pos = range(len(coefs))\n",
    "    \n",
    "    ax.errorbar(\n",
    "        coefs,\n",
    "        y_pos,\n",
    "        xerr=1.96 * ses,\n",
    "        fmt='o',\n",
    "        color=\"darkorange\",\n",
    "        ecolor=\"gray\"\n",
    "    )\n",
    "    \n",
    "    for (y, val) in zip(y_pos, coefs):\n",
    "        ax.text(val + 0.02, y + 0.025, f\"{val:.2f}\", va=\"center\", fontsize=11)\n",
    "    \n",
    "    ax.axvline(0, linestyle=\"--\", color=\"gray\")\n",
    "    ax.set_yticks(y_pos)\n",
    "    ax.set_yticklabels(labels, fontsize=13)\n",
    "    ax.set_title(titles[i], pad=8, size=15)\n",
    "    ax.set_xlabel(\"Coefficient\", size=13)\n",
    "    ax.set_ylabel(\"\")\n",
    "    ax.grid(axis=\"y\", linestyle=\":\", alpha=0.5)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"figure_B1.png\", dpi=600, bbox_inches=\"tight\")\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c85adfea-16f1-4cca-b265-5b7d499d80d9",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "10f156cf-6670-4be3-a4a6-3f68780bfd55",
   "metadata": {},
   "source": [
    "# 2. Vote exp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93835e7e-1cee-4741-91f8-6e0c47c924ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "df[\"vignette_treatment\"] = df[\"vignette_treatment\"].astype(\"category\")\n",
    "df[\"gender\"] = df[\"gender\"].astype(\"category\")\n",
    "\n",
    "outcomes = [\n",
    "    \"legitimacy_vignette\",\n",
    "    \"fairness_vignette\",\n",
    "    \"trust_vignette\",\n",
    "    \"acceptance_vignette\"\n",
    "]\n",
    "\n",
    "titles = [\n",
    "    \"(a) Legitimacy\",\n",
    "    \"(b) Fairness\",\n",
    "    \"(c) Trust\",\n",
    "    \"(d) Acceptance\"\n",
    "]\n",
    "\n",
    "coef_list = []\n",
    "se_list = []\n",
    "label_list = []\n",
    "models = {}\n",
    "\n",
    "control_vars = (\n",
    "    \"+ age \"\n",
    "    \"+ C(gender) \"\n",
    "    \"+ income_cat \"\n",
    "    \"+ living_with_spouse \"\n",
    "    \"+ home_owner \"\n",
    "    \"+ settlement_size \"\n",
    "    \"+ years_in_korea \"\n",
    ")\n",
    "\n",
    "# ---------------------------------------------------------\n",
    "# 3. outcome interaction  (WITH controls)\n",
    "#    outcome ~ C(treatment) * vote_experience + controls\n",
    "# ---------------------------------------------------------\n",
    "for outcome in outcomes:\n",
    "    formula = f\"{outcome} ~ C(vignette_treatment) * vote_experience \" + control_vars\n",
    "    model = smf.ols(formula, data=df).fit()\n",
    "    models[outcome] = model  \n",
    "\n",
    "    # ---------- Full Summary ----------\n",
    "    print(f\"\\n================ FULL SUMMARY for {outcome} =================\")\n",
    "    print(model.summary())\n",
    "\n",
    "    coef = model.params\n",
    "    se = model.bse\n",
    "    \n",
    "    terms = [name for name in coef.index if \"vote_experience\" in name]\n",
    "    coef_vals = [coef[t] for t in terms]\n",
    "    se_vals = [se[t] for t in terms]\n",
    "    \n",
    "    coef_list.append(coef_vals)\n",
    "    se_list.append(se_vals)\n",
    "    label_list.append(terms)\n",
    "\n",
    "# ---------------------------------------------------------\n",
    "# 4. 2×2 multi-panel plot \n",
    "# ---------------------------------------------------------\n",
    "fig, axes = plt.subplots(2, 2, figsize=(14, 8))\n",
    "axes = axes.flatten()\n",
    "\n",
    "for i, ax in enumerate(axes):\n",
    "    coefs = coef_list[i]\n",
    "    ses = se_list[i]\n",
    "    labels = label_list[i]\n",
    "    y_pos = range(len(coefs))\n",
    "\n",
    "    ax.errorbar(\n",
    "        coefs,\n",
    "        y_pos,\n",
    "        xerr=[1.92 * s for s in ses],\n",
    "        fmt='o',\n",
    "        color=\"darkorange\",\n",
    "        ecolor=\"gray\"\n",
    "    )\n",
    "\n",
    "    for (y, val) in zip(y_pos, coefs):\n",
    "        ax.text(val + 0.05, y + 0.05, f\"{val:.2f}\", va=\"center\", fontsize=12)\n",
    "\n",
    "    ax.axvline(0, linestyle=\"--\", color=\"gray\")\n",
    "\n",
    "    ax.set_yticks(y_pos)\n",
    "    ax.set_yticklabels(labels, fontsize=14)\n",
    "    ax.grid(axis=\"y\", linestyle=\":\", alpha=0.5)\n",
    "    ax.set_title(titles[i], fontsize=17, pad=10)\n",
    "    ax.set_xlabel(\"Treatment × Vote Experience\", fontsize=14)\n",
    "    ax.set_ylabel(\"\")\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"figure_B2.png\", dpi=600, bbox_inches=\"tight\")\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b624f34-695d-44d6-9afc-ad6a24385bf2",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "ac3fc884-1920-4f69-8ca4-1c785d07ad6a",
   "metadata": {},
   "source": [
    "# 3. vote count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6b9d550-29fd-4e08-81ea-a52e0be4773e",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_excel(r\"\\df.xlsx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a99a7768-ba5c-4d29-8e45-cc974453d80e",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "df[\"vignette_treatment\"] = df[\"vignette_treatment\"].astype(\"category\")\n",
    "df[\"gender\"] = df[\"gender\"].astype(\"category\")\n",
    "\n",
    "outcomes = [\n",
    "    \"legitimacy_vignette\",\n",
    "    \"fairness_vignette\",\n",
    "    \"trust_vignette\",\n",
    "    \"acceptance_vignette\"\n",
    "]\n",
    "\n",
    "titles = [\n",
    "    \"(a) Legitimacy\",\n",
    "    \"(b) Fairness\",\n",
    "    \"(c) Trust\",\n",
    "    \"(d) Acceptance\"\n",
    "]\n",
    "\n",
    "coef_list = []\n",
    "se_list = []\n",
    "label_list = []\n",
    "models = {}\n",
    "\n",
    "control_vars = (\n",
    "    \"+ age \"\n",
    "    \"+ C(gender) \"\n",
    "    \"+ income_cat \"\n",
    "    \"+ living_with_spouse \"\n",
    "    \"+ home_owner \"\n",
    "    \"+ settlement_size \"\n",
    "    \"+ years_in_korea \"\n",
    ")\n",
    "\n",
    "for outcome in outcomes:\n",
    "    formula = f\"{outcome} ~ C(vignette_treatment) * vote_count \" + control_vars\n",
    "    model = smf.ols(formula, data=df).fit()\n",
    "    models[outcome] = model\n",
    "\n",
    "    print(f\"\\n================ FULL SUMMARY for {outcome} =================\")\n",
    "    print(model.summary())\n",
    "\n",
    "    coef = model.params\n",
    "    se = model.bse\n",
    "\n",
    "    # vote_count 포함된 main + interaction만 선택\n",
    "    terms = [name for name in coef.index if \"vote_count\" in name]\n",
    "    coef_vals = [coef[t] for t in terms]\n",
    "    se_vals = [se[t] for t in terms]\n",
    "\n",
    "    coef_list.append(coef_vals)\n",
    "    se_list.append(se_vals)\n",
    "    label_list.append(terms)\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(14, 8))\n",
    "axes = axes.flatten()\n",
    "\n",
    "for i, ax in enumerate(axes):\n",
    "    coefs = coef_list[i]\n",
    "    ses = se_list[i]\n",
    "    labels = label_list[i]\n",
    "    y_pos = np.arange(len(coefs))\n",
    "\n",
    "    # Errorbar\n",
    "    ax.errorbar(\n",
    "        coefs,\n",
    "        y_pos,\n",
    "        xerr=[1.96 * s for s in ses],\n",
    "        fmt='o',\n",
    "        color=\"darkorange\",\n",
    "        ecolor=\"gray\"\n",
    "    )\n",
    "\n",
    "    for (y, val) in zip(y_pos, coefs):\n",
    "        ax.text(\n",
    "            val,\n",
    "            y + 0.08,   # 숫자를 위로 올림\n",
    "            f\"{val:.2f}\",\n",
    "            ha=\"center\",\n",
    "            fontsize=12\n",
    "        )\n",
    "\n",
    "    # 0선\n",
    "    ax.axvline(0, linestyle=\"--\", color=\"gray\")\n",
    "\n",
    "    # ytick\n",
    "    ax.set_yticks(y_pos)\n",
    "    ax.set_yticklabels(labels, fontsize=14)\n",
    "\n",
    "    xmin = min(coefs) - 0.5\n",
    "    xmax = max(coefs) + 2.5\n",
    "    ax.set_xlim(xmin, xmax)\n",
    "\n",
    "    # grid\n",
    "    ax.grid(axis=\"y\", linestyle=\":\", alpha=0.5)\n",
    "\n",
    "    ax.set_title(titles[i], fontsize=17, pad=10)\n",
    "    ax.set_xlabel(\"Treatment × Vote Count\", fontsize=14)\n",
    "    ax.set_ylabel(\"\")\n",
    "\n",
    "plt.tight_layout(pad=2.5)\n",
    "plt.savefig(\"figure_1.png\", dpi=600, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b57251fb-c267-456f-9d4c-91d876bc9e4f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1eb4d9fc-d706-427c-8ebd-52e08cf68e74",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18a03480-665e-40cb-ac5f-b78a61755080",
   "metadata": {},
   "outputs": [],
   "source": [
    "df[\"vignette_treatment\"] = df[\"vignette_treatment\"].astype(\"category\")\n",
    "df[\"gender\"] = df[\"gender\"].astype(\"category\")\n",
    "\n",
    "# Outcomes and titles\n",
    "outcomes = [\n",
    "    \"legitimacy_vignette\",\n",
    "    \"fairness_vignette\",\n",
    "    \"trust_vignette\",\n",
    "    \"acceptance_vignette\"\n",
    "]\n",
    "\n",
    "titles = [\n",
    "    \"(a) Legitimacy\",\n",
    "    \"(b) Fairness\",\n",
    "    \"(c) Trust\",\n",
    "    \"(d) Acceptance\"\n",
    "]\n",
    "\n",
    "controls = (\n",
    "    \"+ age + C(gender) + income_cat + living_with_spouse \"\n",
    "    \"+ home_owner + settlement_size + years_in_korea\"\n",
    ")\n",
    "\n",
    "effects_0, ses_0 = {}, {}\n",
    "effects_4, ses_4 = {}, {}\n",
    "\n",
    "# --------------------------------------------\n",
    "# Estimate treatment effects for VC=0 & VC=4\n",
    "# --------------------------------------------\n",
    "for outcome in outcomes:\n",
    "\n",
    "    formula = f\"{outcome} ~ C(vignette_treatment)*vote_count {controls}\"\n",
    "    model = smf.ols(formula, data=df).fit()\n",
    "\n",
    "    b = model.params\n",
    "    se = model.bse\n",
    "\n",
    "    # vote_count = 0 (baseline)\n",
    "    eff0_T2 = b.get(\"C(vignette_treatment)[T.2]\", 0)\n",
    "    eff0_T3 = b.get(\"C(vignette_treatment)[T.3]\", 0)\n",
    "\n",
    "    se0_T2 = se.get(\"C(vignette_treatment)[T.2]\", 0)\n",
    "    se0_T3 = se.get(\"C(vignette_treatment)[T.3]\", 0)\n",
    "\n",
    "    effects_0[outcome] = [eff0_T2, eff0_T3]\n",
    "    ses_0[outcome]     = [se0_T2, se0_T3]\n",
    "\n",
    "    # vote_count = 4\n",
    "    eff4_T2 = eff0_T2 + 4 * b.get(\"C(vignette_treatment)[T.2]:vote_count\", 0)\n",
    "    eff4_T3 = eff0_T3 + 4 * b.get(\"C(vignette_treatment)[T.3]:vote_count\", 0)\n",
    "\n",
    "    # CI for vote_count=4 effect\n",
    "    se4_T2 = np.sqrt(\n",
    "        se0_T2**2 + (4*se.get(\"C(vignette_treatment)[T.2]:vote_count\",0))**2\n",
    "    )\n",
    "    se4_T3 = np.sqrt(\n",
    "        se0_T3**2 + (4*se.get(\"C(vignette_treatment)[T.3]:vote_count\",0))**2\n",
    "    )\n",
    "\n",
    "    effects_4[outcome] = [eff4_T2, eff4_T3]\n",
    "    ses_4[outcome]     = [se4_T2, se4_T3]\n",
    "\n",
    "\n",
    "# --------------------------------------------\n",
    "# 2×2 subplot with legend in each plot\n",
    "# --------------------------------------------\n",
    "patterns = [\"///\", \"xxx\"]\n",
    "fig, axes = plt.subplots(2, 2, figsize=(14, 9))\n",
    "axes = axes.flatten()\n",
    "\n",
    "for i, outcome in enumerate(outcomes):\n",
    "    ax = axes[i]\n",
    "\n",
    "    x_labels = [\"Treatment 2\", \"Treatment 3\"]\n",
    "    x = np.arange(len(x_labels))\n",
    "\n",
    "    y0 = effects_0[outcome]\n",
    "    y4 = effects_4[outcome]\n",
    "    se0 = ses_0[outcome]\n",
    "    se4 = ses_4[outcome]\n",
    "\n",
    "    width = 0.35\n",
    "\n",
    "    # vote_count = 0 (left bars)\n",
    "    ax.bar(x - width/2, y0, width, yerr=[1.96*s for s in se0],\n",
    "           label=\"vote_count = 0\", alpha=0.70, capsize=4, hatch=patterns[0])\n",
    "\n",
    "    # vote_count = 4 (right bars)\n",
    "    ax.bar(x + width/2, y4, width, yerr=[1.96*s for s in se4],\n",
    "           label=\"vote_count = 4\", alpha=0.70, capsize=4, hatch=patterns[1])\n",
    "\n",
    "    # Numeric labels above bars\n",
    "    for idx, val in enumerate(y0):\n",
    "        ax.text(x[idx] - width/2, val - 0.2, f\"{val:.2f}\",\n",
    "                ha='center', fontsize=14)\n",
    "    for idx, val in enumerate(y4):\n",
    "        ax.text(x[idx] + width/2, val - 0.2, f\"{val:.2f}\",\n",
    "                ha='center', fontsize=14)\n",
    "\n",
    "    # zero line\n",
    "    ax.axhline(0, linestyle=\"--\", color=\"gray\")\n",
    "\n",
    "    ax.grid(axis=\"y\", linestyle=\":\", alpha=0.5)\n",
    "\n",
    "    # ytick font size\n",
    "    ax.set_xticks(x)\n",
    "    ax.set_xticklabels(x_labels, fontsize=15)\n",
    "\n",
    "    ax.set_title(titles[i], fontsize=17, pad=10)\n",
    "    ax.set_ylabel(\"Estimated Treatment Effect\", fontsize=15)\n",
    "\n",
    "\n",
    "    ax.legend(fontsize=14)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"figure_2.png\", dpi=600, bbox_inches=\"tight\")\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd561fa4-4166-4451-9243-beea0745c36a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cef057d8-47f1-4517-8c1b-61a657711db1",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
